package com.seven.commons;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author sevenDay
 * @classname BeanUtils
 * @description: 描述TODO
 * @date 2018/8/1
 */
public class BeanUtils {

    private static final ConcurrentHashMap<Class, Field[]> FIELDS_CAHCE = new ConcurrentHashMap<Class, Field[]>();
    /**
     * 将对象转化为Map的属性
     *
     * @param obj
     * @return
     */
    public static Map<String, Object> objectToMap(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>(8);
        Class<?> clazz = obj.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            String fieldName = field.getName();
            Object value = null;
            try {
                value = field.get(obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            map.put(fieldName, value);
        }
        return map;
    }

    /**
     * object 转化为map，包括父类信息
     * @param obj
     * @return
     */
    public static Map<String, Object> objectToMapAll(Object obj) {
        if(obj == null){
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        for(Class<?> clazz = obj.getClass(); clazz != Object.class ; clazz = clazz.getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                try {
                    map.put(field.getName(), field.get(obj));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

    /**
     * mao转化为Object
     * @param map
     * @param beanClass
     * @return
     */
    public static Object mapToObject(Map<String, Object> map, Class<?> beanClass){
        if (map == null){
            return null;
        }
        Object obj = null;
        try {
            obj = beanClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field f : fields) {
            int m = f.getModifiers();
            if(Modifier.isStatic(m) || Modifier.isFinal(m)){
                continue;
            }
            //设置访问属性
            f.setAccessible(true);
            try {
                //map.get(f.getName())当这个是一个class的时候
                String filedName = f.getName();
                if (Objects.isNull(map.get(filedName))) {
                    f.set(obj, map.get(filedName));
                    continue;
                }
                final boolean hashMap = map.get(filedName).getClass().getName().endsWith("Map");
                if (hashMap) {
                    Map<String, Object> innerMap = (Map<String, Object>) map.get(filedName);
                    Object in = f.getType().newInstance();
                    Field[] fs = in.getClass().getDeclaredFields();
                    for (Field innerI : fs) {
                        innerI.setAccessible(true);
                        innerI.set(in, Long.parseLong(innerMap.get(innerI.getName()).toString()));
                    }
                    f.set(obj, in);

                } else {
                    f.set(obj, map.get(f.getName()));
                }

            } catch (Exception e) {
               e.printStackTrace();
            }
        }
        return obj;
    }
    /**
     * map转化为对象，包括所有的父类信息
     *
     * @param map
     * @param beanClass
     * @return
     */
    public static Object mapToObjectAll(Map<String, Object> map, Class<?> beanClass) {
        if (map == null) {
            return null;
        }
        Object obj = null;
        try {
            obj = beanClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // 获取所有父类的信息定义
        for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                    continue;
                }
                field.setAccessible(true);
                try {
                    field.set(obj, map.get(field.getName()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return obj;
    }
    public static String toString(Object obj) {
        if (obj == null) {
            return "null";
        }
        Class cl = obj.getClass();
        if (isPrimitive(obj)) {
            return String.valueOf(obj);
        } else if (obj instanceof Enum) {
            return ((Enum) obj).name();
        } else if (obj instanceof Date) {
            return String.valueOf(((Date) obj).getTime());
        } else if (obj instanceof Calendar) {
            return String.valueOf(((Calendar) obj).getTime().getTime());
        } else if (cl.isArray()) {
            String r = "[";
            int len = Array.getLength(obj);
            for (int i = 0; i < len; i++) {
                if (i > 0) {
                    r += ",";
                }
                Object val = Array.get(obj, i);
                r += toString(val);
            }
            return r + "]";
        } else if (obj instanceof Collection) {
            Collection tempCol = (Collection) obj;
            Iterator it = tempCol.iterator();
            String r = "[";
            for (int i = 0; it.hasNext(); i++) {
                if (i > 0) {
                    r += ",";
                }
                Object val = it.next();
                r += toString(val);
            }
            return r + "]";
        } else if (obj instanceof Map) {
            Map tempMap = (Map) obj;
            String r = "{";
            Iterator it = tempMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry entry = (Map.Entry) it.next();
                Object key = entry.getKey();
                r += toString(key);
                r += "=";
                Object val = entry.getValue();
                r += toString(val);
                if (it.hasNext()) {
                    r += ",";
                }
            }
            return r + "}";
        } else if (obj instanceof Class) {
            Class tmpCls = (Class) obj;
            return tmpCls.getName();
        }
        String r = cl.getName();
        do {
            Field[] fields = FIELDS_CAHCE.get(cl);
            if (null == fields) {
                fields = cl.getDeclaredFields();
                if (null != fields) {
                    AccessibleObject.setAccessible(fields, true);
                }
                FIELDS_CAHCE.put(cl, fields);
            }
            if (null == fields || fields.length == 0) {
                cl = cl.getSuperclass();
                continue;
            }
            r += "[";
            // get the names and values of all fields
            for (Field f : fields) {
                if (Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
                if (f.isSynthetic() || f.getName().indexOf("this$") != -1) {
                    continue;
                }
                r += f.getName() + "=";
                try {
                    Object val = f.get(obj);
                    r += toString(val);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                r += ",";

            }
            String comma = ",";
            if (r.endsWith(comma)) {
                r = r.substring(0, r.length() - 1);
            }
            r += "]";
            cl = cl.getSuperclass();
        } while (cl != null);
        return r;
    }
    public static boolean isPrimitive(Object obj) {
        boolean rv = obj.getClass().isPrimitive() || obj instanceof String || obj instanceof Integer
                || obj instanceof Long || obj instanceof Byte || obj instanceof Character || obj instanceof Boolean
                || obj instanceof Short || obj instanceof Float || obj instanceof Double || obj instanceof BigDecimal
                || obj instanceof BigInteger;
        return rv;
    }
    /**
     * @descrp:判断是否是基本类型 int long void short
     * @auther: sevenDay
     * @date: 2019/1/3 17:22
     * @param clazz :
     * @return : boolean
     */
    public static boolean isPrimitive(Class clazz){

        return clazz.isPrimitive();
    }

    /**
     * @descrp:判断是否是包装类型的基本类型
     * @auther: sevenDay
     * @date: 2019/1/3 17:24
     * @param clazz :
     * @return : boolean
     */
    public static boolean isWrapClass(Class clazz) {
        try {
            return ((Class) clazz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * @descrp:排除基本类型和包装类型
     * @auther: sevenDay
     * @date: 2019/1/3 17:26
     * @param clazz :
     * @return : boolean
     */
    public static boolean judgeBaseTypeExcludeWrapClass(Class clazz){

        if (isPrimitive(clazz)){
            return true;
        }
        return isWrapClass(clazz);
    }
}
